package com.example.kotlincoroutine

import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.supervisorScope
import kotlinx.coroutines.yield
import org.junit.Test
import java.lang.IllegalArgumentException
import java.util.Hashtable
import kotlin.system.measureTimeMillis

class CoroutineTest02 {

    //把函数变成协程到方式用runBlocking
    @Test
    fun `test scope cancel`() = runBlocking {//如果没有阻塞，那么就要返回runBlocking<Unit>
        //通过CoroutineScope这样构建的协程并没有继承runBlocking的上下文，并没有去阻塞runBlocking的协程，因此CoroutineScope的等待会造成没有对runBlocking返回，所以下面的代码会报错(No tests found for given includes: [com.example.kotlincoroutine.CoroutineTest02.test coroutine builder](--tests filter))，
        val scope = CoroutineScope(Dispatchers.Default)
        scope.launch {
            delay(1000)
            println("Job1 finished")
        }

        scope.launch {
            delay(1000)
            println("Job2 finished")
        }
        //delay(2000)//加了这一句，就是说让runBlocking有了阻塞，得以让CoroutineScope的协程可以进行


        //这里表示runBlocking阻塞了，然后取消CoroutineScope的协程
        delay(100)
        //1、取消作用域会取消它的子协程
        scope.cancel()
        delay(2000)
    }

    @Test
    fun `test brother cancel`() = runBlocking<Unit> {
        val scope = CoroutineScope(Dispatchers.Default)
        val job1 = scope.launch {
            delay(1000)
            println("Job1 finished")
        }

        val job2 = scope.launch {
            delay(1000)
            println("Job2 finished")
        }
        //演示效果：2、兄弟被取消了，不会影响其他的协程
        job1.cancel()
        delay(2000)
    }

    @Test
    fun `test cancellationException`() = runBlocking<Unit> {
        //GlobalScope没有继承runBlocking，所以代码不会执行(runBlocking执行先结束了，runBlocking不去等待GlobalScope的执行先返回了，所以GlobalScope不会执行了)
        val job1 = GlobalScope.launch {
            delay(1000)
            println("Job1 finished")
        }
        //job1.join()//这样才会执行，加这句是让协程可以优先执行
        //delay(2000)//或者这样才会执行
    }

    @Test
    fun `test cancellationException2`() = runBlocking<Unit> {
        //下面演示异常抛出情况：delay执行时，job1.join加入了，然后等待1000，
        val job1 = GlobalScope.launch {
            try {
                println("11111Job1 finished")
                delay(1000)
                println("Job1 finished")
            } catch (e: Exception) {
                //JobCancellationException: StandaloneCoroutine was cancelled; job="coroutine#2":StandaloneCoroutine{Cancelling}@dfaeba7
                e.printStackTrace()
            }
        }
        //想演示的效果就是job1进入执行状态时，发现被取消过了，因此抛出异常
        //方式一
//        delay(100)
//        job1.cancel()
//        job1.join()
        //合并写法
//        job1.cancelAndJoin()

        //方式二
//        job1.cancel()
//        delay(2000)

        //自定义抛出异常
        job1.cancel(CancellationException("我抛出的异常"))
        delay(2000)
    }

    @Test
    fun `test cancel cpu task by isActive`() = runBlocking<Unit> {
        //可以取消的有withContext 和 delay函数
        //演示不可取消的情况：cpu密集型

        val time = System.currentTimeMillis()
        val job1 = launch(Dispatchers.Default) {
            var nextPrintTime = time
            var i = 0
            while (i < 5) {
                if (System.currentTimeMillis() >= nextPrintTime) {
                    i++
                    println("打印：$nextPrintTime")
                    nextPrintTime += 500
                }
            }
        }
        delay(1300)
        println("main waiting")
        job1.cancelAndJoin()
        println("main quit")
    }

    @Test
    fun `test cancel cpu task by ensureActive`() = runBlocking<Unit> {
        //可以取消的有withContext 和 delay函数
        //演示不可取消的情况：cpu密集型

        val time = System.currentTimeMillis()
        val job1 = launch(Dispatchers.Default) {
            var nextPrintTime = time
            var i = 0
            while (i < 5) {
                ensureActive()//这个会检查并且抛出异常
                try {
                    if (System.currentTimeMillis() >= nextPrintTime) {
                        i++
                        println("打印：$nextPrintTime")
                        nextPrintTime += 500
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    println("抛出异常：${e.message}")
                }
            }
        }
        delay(1300)
        println("main waiting")
        job1.cancelAndJoin()
        println("main quit")
    }
    @Test
    fun `test cancel cpu task by yield`() = runBlocking<Unit> {
        //可以取消的有withContext 和 delay函数
        //演示不可取消的情况：cpu密集型

        val time = System.currentTimeMillis()
        val job1 = launch(Dispatchers.Default) {
            var nextPrintTime = time
            var i = 0
            while (i < 5) {
                yield()//如果取消了，那么这个也会抛出异常
                try {
                    if (System.currentTimeMillis() >= nextPrintTime) {
                        i++
                        println("打印：$nextPrintTime")
                        nextPrintTime += 500
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                    println("抛出异常：${e.message}")
                }
            }
        }
//        delay(1300)
//        println("main waiting")
//        job1.cancelAndJoin()
//        println("main quit")

        //7个阶段
        //首先是电源按下之后芯片代码开始执行，加载引导程序bootloader
        //bootlader会去拉起os系统，启动linux kernel内核，去查找一个init.rc文件启动init进程，初始化进程之后会fork一个zygote进程

    }
}